package com.zxy.supplier_system.server.repository

import com.zxy.supplier_system.server.entity.Market
import com.zxy.supplier_system.server.entity.MarketDeliveryOrder
import com.zxy.supplier_system.server.entity.SystemService
import com.zxy.supplier_system.server.utils.SpecificationUtils
import com.zxy.supplier_system.server.utils.joinOnce
import org.springframework.data.jpa.domain.Specification
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaSpecificationExecutor
import java.time.LocalDate
import java.time.OffsetDateTime

interface MarketDeliveryOrderRepository : JpaRepository<MarketDeliveryOrder, Int>,
    JpaSpecificationExecutor<MarketDeliveryOrder> {

    fun findByIdAndMarket_SystemService(id: Int, market_systemService: SystemService): MarketDeliveryOrder?

    object Specifications {
        fun marketSaleManagerEqual(employeeId: Int): Specification<MarketDeliveryOrder> {
            return Specification { root, _, criteriaBuilder ->
                MarketRepository.Specifications.saleManagerEqual(root.joinOnce("market"), criteriaBuilder, employeeId)
            }
        }

        fun marketShoppingGuidesContains(employeeId: Int): Specification<MarketDeliveryOrder> {
            return Specification { root, query, criteriaBuilder ->
                MarketRepository.Specifications.shoppingGuidesContains(
                    root.joinOnce("market"),
                    criteriaBuilder,
                    query,
                    employeeId
                )
            }
        }

        fun createdDateTimeGreaterThanOrEqualTo(startDate: LocalDate?): Specification<MarketDeliveryOrder> {
            return Specification { root, _, criteriaBuilder ->
                startDate?.let {
                    criteriaBuilder.greaterThanOrEqualTo(root.get("createdDateTime"), it)
                }
            }
        }

        fun createdDateTimeLessThan(endDate: LocalDate?): Specification<MarketDeliveryOrder> {
            return Specification { root, _, criteriaBuilder ->
                endDate?.let {
                    criteriaBuilder.lessThan(root.get("createdDateTime"), it)
                }
            }
        }

        fun validatedDateTimeGreaterThanOrEqualTo(startDate: LocalDate?): Specification<MarketDeliveryOrder> {
            return Specification { root, _, criteriaBuilder ->
                startDate?.let {
                    criteriaBuilder.greaterThanOrEqualTo(root.get("validatedDateTime"), it)
                }
            }
        }

        fun validatedDateTimeLessThanOrEqualTo(endDate: LocalDate?): Specification<MarketDeliveryOrder> {
            return Specification { root, _, criteriaBuilder ->
                endDate?.let {
                    criteriaBuilder.lessThanOrEqualTo(root.get("validatedDateTime"), it)
                }
            }
        }

        fun marketIn(marketIds: List<Int>): Specification<MarketDeliveryOrder> {
            return SpecificationUtils.`in`({ root ->
                root.joinOnce<MarketDeliveryOrder, Market>("market").get("id")
            }, marketIds)
        }

        fun statusEqual(status: MarketDeliveryOrder.Status?): Specification<MarketDeliveryOrder> {
            return Specification { root, query, criteriaBuilder ->
                if (status == null) {
                    null
                } else {
                    when (status) {
                        MarketDeliveryOrder.Status.WAIT_VALIDATED -> criteriaBuilder.isNull(root.get<OffsetDateTime>("validatedDateTime"))
                        MarketDeliveryOrder.Status.VALIDATED -> criteriaBuilder.and(
                            criteriaBuilder.isNotNull(
                                root.get<OffsetDateTime>(
                                    "validatedDateTime"
                                )
                            ),
                            criteriaBuilder.isNull(root.get<OffsetDateTime>("auditedDateTime"))
                        )

                        MarketDeliveryOrder.Status.AUDITED ->  criteriaBuilder.isNotNull(root.get<OffsetDateTime>("auditedDateTime"))
                    }
                }
            }
        }

        fun numberContains(number: String?): Specification<MarketDeliveryOrder> {
            return SpecificationUtils.contains({ root ->
                root.get("number")
            }, number)
        }
    }


}

